package com.wdl.modules.myhouse.security.controller;

import com.alibaba.fastjson.JSONObject;
import com.auth0.jwt.exceptions.JWTDecodeException;
import com.auth0.jwt.exceptions.TokenExpiredException;
import com.wdl.modules.myhouse.dao.SysUserDao;
import com.wdl.modules.myhouse.dao.security.SecurityDao;
import com.wdl.modules.myhouse.security.common.SecurityConstant;
import com.wdl.modules.myhouse.security.entity.UserInfo;
import com.wdl.modules.myhouse.service.FileService;
import com.wdl.modules.myhouse.service.SysUserService;
import com.wdl.modules.myhouse.service.UserService;
import com.wdl.modules.myhouse.common.Code;
import com.wdl.modules.myhouse.common.Constant;
import com.wdl.modules.myhouse.common.Result;
import com.wdl.modules.myhouse.service.oauth2.Oauth2WeiboService;
import com.wdl.modules.myhouse.utils.util.*;
import com.wdl.modules.myhouse.vo.UserVo;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
import org.springframework.web.bind.annotation.*;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.*;
import java.util.concurrent.TimeUnit;

/**
 * @author 昏昏的君
 */
@Api(tags = "安全相关controller")
@RestController
@RequestMapping("/security")
@Slf4j
public class SecurityController {


    @Value("${oauth2.weibo.key}")
    private String appKey;
    @Value("${oauth2.weibo.secret}")
    private String appSecret;
    @Value("${oauth2.weibo.redirect-url}")
    private String redirectUrl;
    @Value("${oauth2.weibo.baseUrl}")
    private String weiboBaseUrl;


    @Autowired
    private SysUserService sysuserService;
    @Autowired
    private PasswordEncoder passwordEncoder;
    @Autowired
    private AuthenticationSuccessHandler successHandler;
    @Autowired
    private SecurityDao securityDao;
    @Autowired
    private SysUserDao sysUserDao;
    @Autowired
    private UserService userService;
    @Autowired
    private FileService fileService;

    @Autowired
    private RedisUtil redisUtil;
    @Autowired
    private Oauth2WeiboService weiboService;


    @ApiOperation("爬取所有分类文件信息")
    @GetMapping("/runSpider")
    public Result<String> spider(){
        fileService.saveSpiderData();
        return  new Result<String>().ok("爬虫以及开始工作,可以到后台查看进度");
    }

    @ApiOperation("爬取专题类文件信息")
    @GetMapping("/runSpider1")
    public Result<String> spider1(){
        fileService.saveSpiderTopicRes();
        return  new Result<String>().ok("爬虫以及开始工作,可以到后台查看进度");
    }

    /**
     * 微博登录用户与系统用户身份对照关系
     * "WEIBO:"+微博用户ID=USERNAME
     * "666666"=PASSWORD,
     *
     * @param code
     * @param req
     * @param resp
     * @return
     * @throws ServletException
     * @throws IOException
     */
    @ApiOperation("微博登录成功回调页")
    @GetMapping("/oauth2/{platform}/save")
    public Result<UserVo> weiboSuccess(@RequestParam("code") String code, HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        return  weiboService.weiboLoginSuccess(code, req, resp);
    }


    @ApiOperation("微博登录失败回调页")
    @GetMapping("/oauth2/fail")
    public void weiboFail(HttpServletResponse response) {
        try {
            response.sendRedirect("http://localhost:8080/");
            response.getWriter().println(JsonUtil.obj2String(new Result<String>().error(Code.UNAUTHORIZED.getCode(),"授权取消")));
        } catch (IOException e) {
            e.printStackTrace();
        }
    }


    @ApiOperation("获取微博应用信息")
    @GetMapping("/oauth2/{platform}")
    public Result<JSONObject> weiboMessage(@PathVariable("platform") String platform) {
        Result<JSONObject> res = new Result<>();
        HashMap<String, Object> map = new HashMap<>();
        map.put("appKey", appKey);
        map.put("appSecret", appSecret);
        map.put("redirectUrl", redirectUrl);
        JSONObject json = new JSONObject(map);
        res.setData(json);
        return res;
    }


    @ApiOperation("发送邮箱验证码")
    @GetMapping("/sendMail/{mailAddr}")
    public Result<String> sendMailCode(@PathVariable("mailAddr") String mailAddr) {
        String value = redisUtil.getValue(mailAddr);
        if (value == null) {
            // 当前邮箱在规定时间内未发送过验证码
            sendMail(mailAddr);
        } else {
            // 当前邮箱已经发送过验证码,并且验证码尚未过期
            try {
                log.info("当前邮箱短时间已经发送过验证码了");
                String code = JWTUtils.getToken(value).getClaim("CODE").asString();
                String expired_time = JWTUtils.getToken(value).getClaim("EXPIRED_TIME").asString();
                if (new Date().after(new Date(expired_time))) {
                    //可以重新发送邮件
                    sendMail(mailAddr);
                }
            } catch (JWTDecodeException e) {
                log.warn("邮箱发送验证码，jwt解析异常，已经重发验证码");
                sendMail(mailAddr);
            }
        }
        return new Result().ok();
    }

    private void sendMail(String mailAddr) {
        Integer code = new Random().nextInt(8999) + 1000;

        HashMap<String, String> map = new HashMap<>();
        map.put("CODE", code.toString());
        Calendar calendar = Calendar.getInstance();
        calendar.add(Calendar.SECOND, 60);
        Date expiredTime = calendar.getTime();
        map.put("EXPIRED_TIME", expiredTime.toString());
        String token = JWTUtils.createToken(map, null);

        redisUtil.setValue(mailAddr, token, Constant.VER_CODE_TIME_OUT, TimeUnit.MINUTES);
        log.info("邮箱验证码:", code);
        EmailUtil.sendSimpleMail(mailAddr, "您的验证码", code.toString());
    }


    @ApiOperation("token续期")
    @GetMapping("/renewal")
    public Result renewal(HttpServletRequest request, HttpServletResponse resp) {
        String token = request.getHeader(SecurityConstant.TOKEN_COOKIE_NAME);
        Integer uid = null;
        Result res = new Result();
        try {
            uid = JWTUtils.getToken(token).getClaim(SecurityConstant.TOKEN_FIELD).asInt();
            String json = redisUtil.getValue(uid.toString());
            if (json == null || json.isEmpty()) {
                //token 已经过期
                res = new Result().error(Code.TOKEN_TIMEOUT.getCode(), Code.TOKEN_TIMEOUT.getMessage());
            } else {
                //正常续期
                redisUtil.setValue(uid.toString(), json, RedisUtil.getTimeOut(1, 3), TimeUnit.HOURS);
                res = new Result().ok();
            }
        } catch (JWTDecodeException e) {
            log.error("JWT解析异常");
            res = new Result().error(Code.TOKEN_UNLEGAL.getCode(), Code.TOKEN_UNLEGAL.getMessage());
        }
        return res;
    }

    @ApiOperation("校验token")
    @GetMapping("/validate")
    public Result validate(HttpServletRequest request, HttpServletResponse response) throws IOException {
        Result res = new Result().ok();
        Object principal = SecurityContextHolder.getContext().getAuthentication().getPrincipal();
        if (principal == null || principal.equals("anonymousUser")) {
            String token = request.getHeader(SecurityConstant.TOKEN_COOKIE_NAME);
            if (token == null) {
                res = new Result().error(Code.TOKEN_NOT_EXISTS.getCode(), "请求头中未找到token,token名应为:" + SecurityConstant.TOKEN_COOKIE_NAME);
            } else {
                //验证token
                try {
                    Integer uid = JWTUtils.getToken(token).getClaim(SecurityConstant.TOKEN_FIELD).asInt();
                    String userJson = redisUtil.getValue(uid.toString());
                    UserInfo userInfo = JsonUtil.string2Obj(userJson, UserInfo.class);
                    if (userInfo == null) {
                        res = new Result().error(Code.TOKEN_NOT_EXISTS.getCode(), Code.TOKEN_NOT_EXISTS.getMessage());
                    }
                } catch (JWTDecodeException e) {
                    log.warn("JWT解析异常");
                    res = new Result().error(Code.TOKEN_UNLEGAL.getCode(), Code.TOKEN_UNLEGAL.getMessage());
                } catch (NullPointerException e) {
                    res = new Result().error(Code.TOKEN_NOT_EXISTS.getCode(), "TOKEN不存在或者已经过期");
                }catch (TokenExpiredException e){
                    res=new Result().error(Code.TOKEN_TIMEOUT.getCode(), Code.TOKEN_TIMEOUT.getMessage());
                }catch(Exception e){
                    res=new Result().error();
                }
            }
        }
        return res;
    }


    @ApiOperation("用户登陆")
    @PostMapping("/login/mail")
    public Result<String> login(@RequestBody(required = false) UserVo userVo) {
        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
        System.out.println(authentication.getPrincipal().toString());
        System.out.println(authentication.getCredentials());
        Result res = new Result<String>().ok();
        res.setData((UserInfo) authentication.getPrincipal());
        return res;
    }


    @ApiOperation("注册用户")
    @PostMapping("/register")
    public Result<String> register(@RequestBody UserVo userVo) {
//        SysUserEntity entity = new SysUserEntity();
////        String password = userVo.getPassword();
//        entity.setUsername(userVo.getUserName());
//        if (password != null) {
//            entity.setPassword(passwordEncoder.encode(password));
//        }
//        userService.save(entity);
        return new Result<String>().ok();
    }

}
